package com.plc.s7;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import cn.hutool.log.level.Level;
import com.github.s7connector.api.DaveArea;
import com.github.s7connector.api.S7Connector;
import com.github.s7connector.impl.serializer.converter.BitConverter;
import com.github.s7connector.impl.serializer.converter.IntegerConverter;
import com.github.s7connector.impl.serializer.converter.RealConverter;
import com.github.s7connector.impl.serializer.converter.StringConverter;
import com.plc.wmsentity.PlcEntity;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ReadPLC {

    Log log = LogFactory.get();

    //Int类型的封装类 用来转义
    private static IntegerConverter intCon = new IntegerConverter();
    //String...
    private static StringConverter strCon = new StringConverter();
    //Boolean...
    private static BitConverter boolCon = new BitConverter();
    //real实数浮点...
    private static RealConverter realCon = new RealConverter();


    //获取到的数据存储
    public String equipmentNo = "";//string
    public Integer equipmentType = null;//int

    public Integer state = null;

    public String errorMessage = "";//string

    public PlcEntity Cyclic_read(S7Connector connector,int dateBaseAddress) {
        String now = DateUtil.now();
        PlcEntity cur = null;
        try {
            byte[] PlcData = null;
            //读取字符串型 设备编号
            PlcData = connector.read(DaveArea.DB, // 选择数据区块
                    dateBaseAddress , // 区块编号
                    50, // 数据值长度 String最小3 随值长度增加
                    0); // 开始位置偏移量
        //  String extract_equipmentNo = strCon.extract(new String().getClass(), PlcData, 0, 0);
            equipmentNo =  byteArrayToString(PlcData,"UTF-8");;
            //读取整型  设备类型
            PlcData = connector.read(DaveArea.DB, // 选择数据区块
                    dateBaseAddress, // 区块编号
                    2, // 数据值长度 int长度2
                    104); // 开始位置 偏移量
            Integer extract_equipmentType = intCon.extract(new Integer(0).getClass(), PlcData, 0, 0);
            equipmentType = extract_equipmentType;
            //设备状态
            PlcData = connector.read(DaveArea.DB, // 选择数据区块
                    dateBaseAddress, // 区块编号
                    2, // 数据值长度 int长度2
                    106); // 开始位置 偏移量

            Integer extract_state = intCon.extract(new Integer(0).getClass(), PlcData, 0, 0);
            state = extract_state;

            //读取字符串型 错误msgs
            PlcData = connector.read(DaveArea.DB, // 选择数据区块
                    dateBaseAddress, // 区块编号
                   512, // 数据值长度 String最小3 随值长度增加
                    108); // 开始位置偏移量
            errorMessage = byteArrayToString(PlcData,"UTF-8");
            connector.close();//关闭链接

        } catch (IOException e) {

            log.log(Level.INFO,"日期{},调用plc地址为：{},失败,无法连接至PLC服务器",now,dateBaseAddress);
        }
        if(state.intValue()==1||state.intValue()==2){
            cur = new PlcEntity(equipmentNo,equipmentType,state,"无");
            log.log(Level.INFO,"日期{},调用plc地址为：{},成功,DB参数为{}",now,dateBaseAddress, JSONUtil.toJsonStr(cur));

        }else {
            cur = new PlcEntity(equipmentNo, equipmentType, state, errorMessage);
            log.log(Level.INFO,"日期{},调用plc地址为：{},成功,DB参数为{}",now,dateBaseAddress, JSONUtil.toJsonStr(cur));
        }
        return cur;
    }

    public static String byteArrayToString(byte[] data, String charsetName) {
        byte[] newBytes = new byte[data.length-2];
        for(int i = 0 ; i< data.length;i++){
            if(i<2){
                data[i]=0;
            }
        }
       // 判断字节顺序
        ByteOrder byteOrder = (data[0] == 0 && data[1] != 0) || (data[0] != 0 && data[1] == 0)
                ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN;

        // 根据字节顺序构建ByteBuffer
        ByteBuffer buffer = ByteBuffer.wrap(data);
        buffer.order(byteOrder);

        // 跳过前两个字节的长度信息
        buffer.position(2);
        String str = null;
        str = new String(data, StandardCharsets.UTF_16BE);
        str=filterCode(str);
        return str;

    }

    // 使用指定字符集解码字节数组为字符串，直到遇到结束符'\0'
    public static String decodeWString(byte[] data, String encoding) {
        StringBuilder stringBuilder = new StringBuilder();
        int i = 0;
        while (i < data.length) {
            char c = (char) ((data[i] & 0xFF) | ((data[i + 1] & 0xFF) << 8));
            if (c == '\0') {
                break;
            }
            stringBuilder.append(c);
            i += 2; // UTF-16编码中每个字符占用2个字节
        }
        return stringBuilder.toString();
    }

    // 检查字符串中是否包含有效的中文字符
    public static boolean containsValidChineseCharacters(String text) {
        if (text == null || text.isEmpty()) {
            return false;
        }
        for (char c : text.toCharArray()) {
            if (c >= '\u4e00' && c <= '\u9fff') { // Unicode中文字符范围
                return true;
            }
        }
        return false;
    }
    //过滤非法字符
    public static String filterCode(String code) {
        // 使用正则表达式匹配字母、数字和汉字，并将其保留
        String regex = "[\\p{L}\\p{N}\\p{IsHan}]+";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(code);

        // 使用StringBuilder来保存匹配的字符
        StringBuilder filteredCode = new StringBuilder();

        while (matcher.find()) {
            filteredCode.append(matcher.group());
        }

        return filteredCode.toString();
    }
}
